package model.pieces;

import java.beans.PropertyChangeListener;

import model.PropertySupport;
import model.memento.Movement;

public class Target extends Piece {

	private enum TargetState {
		FreeTarget, BoxOnTarget, ManOnTarget, ManBoxOnTarget
	}

	/**
	 * Estado de la pieza Target
	 */
	private PropertySupport<TargetState> state;
	/**
	 * Estado que recuerda el estado
	 */
	private TargetState oldState;

	/**
	 * @param x
	 *            <-> col
	 * @param y
	 *            <-> row
	 */
	public Target(int x, int y) {
		super(x, y);
		this.state = new PropertySupport<Target.TargetState>(
				TargetState.FreeTarget);
		this.oldState = this.state.get();
	}

	/**
	 * Cambiar estado de Target a desocupado. No se notifica a los listeners.
	 */
	public void setFreeTargetState() {
		this.state.suspendNotifications(true);
		this.state.set(TargetState.FreeTarget);
		this.state.suspendNotifications(false);
	}

	/**
	 * Cambiar estado de Target a ocupado por Box. Se notifica a los listeners.
	 */
	public void setBoxOnTargetState() {
		this.state.set(TargetState.BoxOnTarget);
	}

	/**
	 * Cambiar estado de Target a ocupado por Man. No se notifica a los
	 * listeners.
	 */
	public void setManOnTargetState() {
		this.state.suspendNotifications(true);
		this.state.set(TargetState.ManOnTarget);
		this.state.suspendNotifications(false);
	}

	/**
	 * @return boolean free
	 */
	public boolean isFree() {
		return this.state.get() == TargetState.FreeTarget;
	}

	/**
	 * @return boolean boxOnTarget
	 */
	public boolean isBoxOnTarget() {
		return this.state.get() == TargetState.BoxOnTarget;
	}

	/**
	 * @see model.pieces.Piece#requestMultiMovement(model.memento.Movement)
	 */
	@Override
	public void requestMultiMovement(Movement move) {
		// Si llega Man a la posicion de Target y esta libre, estado
		// ManOnTarget!!
		if (move.isMovementPosition(col, row)) {
			// Puede estar Man sobre BoxOnTarget, ManBoxOnTarget
			if (isBoxOnTarget()) {
				this.oldState = TargetState.ManBoxOnTarget;
			}
			setManOnTargetState();
		}
	}

	/**
	 * @see model.pieces.Piece#requestSingleMovement(model.memento.Movement)
	 */
	@Override
	public void requestSingleMovement(Movement move) {
		// Si llega Box a la posicion de Target y esta libre, estado
		// BoxOnTarget!! && isFree()
		if (move.isMovementPosition(col, row)) {
			setBoxOnTargetState();
		}
	}

	/**
	 * @see model.pieces.Piece#refuseMovement(model.memento.Movement)
	 */
	@Override
	public void refuseMovement(Movement move) {
		// Target no se mueve pero Man o Box on Target no pudieron moverse.
		if (move.isMovementPosition(col, row)) {
			// volver al estado anterior
			this.state.suspendNotifications(true);
			this.state.set(this.oldState);
			this.state.suspendNotifications(false);
		}
	}

	/**
	 * @see model.pieces.Piece#leavePosition(int, int)
	 */
	@Override
	public void leavePosition(int col, int row) {
		if (this.col == col && this.row == row) {
			// pieza desocupada, recordar anterior estado por si refuse
			leaveState();
		}
	}

	private void leaveState() {
		// Si Man&BoxOnTarget, recordar BoxOnTarget por si refuse de Box
		if (this.oldState == TargetState.ManBoxOnTarget) {
			this.oldState = TargetState.BoxOnTarget;
		} else {
			this.oldState = this.state.get();
			setFreeTargetState();
		}
	}

	/**
	 * Agregar un listener a la lista de state.
	 * 
	 * @param listener
	 */
	public void addTargetStatePropertyListener(PropertyChangeListener listener) {
		this.state.addPropertyChangeListener(listener);
	}

	/**
	 * Borrar un listener de la lista de state.
	 * 
	 * @param listener
	 */
	public void removeTargetStatePropertyListener(
			PropertyChangeListener listener) {
		this.state.removePropertyChangeListener(listener);
	}
}
